package sg4c.frontend;

import java.awt.*;
import java.applet.*;

public abstract class DoubleBufferedApplet extends Applet implements Runnable {

    int fps;
    int frameCount;
    int width, height;
    Thread frameRateControlThread;
    Dimension offDimension;
    Image bufferImage;
    boolean stopped = false;

    long startDrawTime;
    volatile long timeToDraw=0;

    /**
     * Create with default framerate of 12
     *
     */
    public DoubleBufferedApplet() {
        fps = 12;
    }

    public int framerate() {
        return fps;
    }

    public void setFramerate(int fps) {
        this.fps = fps;
    }

    public int frameCount() {
        return frameCount;
    }

    public Image getImage(){
        return bufferImage;
    }

    public void beginDraw(){
        startDrawTime=System.currentTimeMillis();
    }

    public void endDraw(){
        timeToDraw = System.currentTimeMillis() - startDrawTime;
    }

    public float apparentFramerate(){
        return 1000.0f/timeToDraw;
    }

    @Override
    public void setSize(int w, int h) {
        width = w;
        height = h;
        super.setSize(w, h);
        setPreferredSize(new Dimension(w, h));   //set preferrable size
    }

    private void allocateBuffer() {
        bufferImage = createImage(width(), height());
    }

    public int width() {
        return width;
    }

    public int height() {
        return height;
    }

    @Override
    public void start() {
        frameRateControlThread = new Thread(this);
        if( framerate() > 0 ){
            frameRateControlThread.start();
        }
    }

    public void run() {
        int framePerMilliSec = 1000 / fps;
        while (!stopped) {
            repaint();  //generate calls to update()
            frameCount++;
            //delay the drawing
            try {
                long timedelta = timeToDraw;
                
                long sleepTime = framePerMilliSec - timedelta;
                
                if (sleepTime > 0) {
                    Thread.sleep(sleepTime);
                }

            } catch (InterruptedException e) {
                break;
            }
        }
    }

    @Override
    public void stop() {
        stopped = true;
        frameRateControlThread = null;
        bufferImage = null;
    }

    @Override
    public void update(Graphics g) {
        if (bufferImage == null) {

            allocateBuffer();
        }
        // draw new frame into buffer graphic
        draw(bufferImage.getGraphics());
        // draw the current buffer to screen
        g.drawImage(bufferImage, 0, 0, null);

    }

    /**
     * Called whenever the screen should be repainted.
     */
    @Override
    public void paint(Graphics g) {
        
        super.paint(g);
        if (bufferImage != null) {//draw from the bufferImage
            g.drawImage(bufferImage, 0, 0, null);
        }
        
    }

    public abstract void draw(Graphics g);
}
